//
//  ConfiGurableTextView.m
//  CLHComponents
//
//  Created by 曹连华 on 2020/9/8.
//

#import "ConfiGurableTextView.h"
#import <CoreText/CoreText.h>

@interface LinkVO : NSObject

/** 链接的文字 */
@property(nonatomic, copy) NSString *text;
/** 链接的范围 */
@property(nonatomic, assign) NSRange range;
/** 链接数组,因为链接可能是换行的 */
@property(nonatomic, strong) NSArray *rectsArray;

@end

@implementation LinkVO

@end

@interface ConfiGurableTextView () <UITextViewDelegate> {
    CGFloat _minHeight;
}
@property (nonatomic, strong) UILabel *placeholderLabel;
@property (nonatomic, strong) NSMutableArray *linksArray;
/** key 选中的文字
  value 选中的文字对应的RangeString */
@property (nonatomic, strong) NSMutableDictionary<NSString *,NSString*> *selectedStrRangeDic;

@end

@implementation ConfiGurableTextView
- (UILabel *)placeholderLabel {
    if (!_placeholderLabel) {
        _placeholderLabel = [[UILabel alloc]initWithFrame:CGRectMake(8, 2, [UIScreen mainScreen].bounds.size.width, 30)];
        _placeholderLabel.backgroundColor = [UIColor whiteColor];
        _placeholderLabel.textColor = [UIColor lightGrayColor];
        _placeholderLabel.font = [UIFont systemFontOfSize:15];
        _placeholderLabel.text = @"请输入";
    }
    return _placeholderLabel;
}
- (NSMutableDictionary<NSString *,NSString*> *)selectedStrRangeDic {
    if (!_selectedStrRangeDic) {
        _selectedStrRangeDic = [NSMutableDictionary<NSString *,NSString*> dictionary];
    }
    return _selectedStrRangeDic;
}

- (NSMutableArray *)linksArray {
    if (!_linksArray) {
        _linksArray = [NSMutableArray array];

        // 来到这里说明找到链接
        for (NSString *selectedString in self.selectedStrUrlDic.allKeys) {
            NSString *selectedRangeStr = [self.selectedStrRangeDic objectForKey:selectedString];
            NSRange selectedRange = NSRangeFromString(selectedRangeStr);
           
            LinkVO *linkVO = [[LinkVO alloc] init];
            linkVO.text = selectedString;
            linkVO.range = selectedRange;
       
            // 处理矩形框，因为有可能链接是换行存在的
            NSMutableArray *rectArray = [NSMutableArray array];
            // 设置选中的范围
            self.selectedRange = linkVO.range;
            // 设置选中的字符范围的边框
            NSArray *rectsArray = [self selectionRectsForRange:self.selectedTextRange];
            for (UITextSelectionRect *rect in rectsArray) {
                if (rect.rect.size.width == 0 || rect.rect.size.height == 0) {
                    continue;
                }
                if (rect) {
                    [rectArray addObject:rect];
                }
            }
            linkVO.rectsArray = rectArray;
            if (linkVO) {
                [_linksArray addObject:linkVO];
            }
        }
    }
    return _linksArray;
}
- (instancetype)initWithFrame:(CGRect)frame supportAttributed:(BOOL)supportAttributed {
    self = [self initWithFrame:frame];
    if (self) {
        if (supportAttributed) {
            UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(textViewDidTouched:)];
            [self addGestureRecognizer:tap];
            [self setEditable:NO];
            [self setUserInteractionEnabled:YES];
        }
    }
    return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        _minHeight = frame.size.height;
        self.maxLength = -1;
        self.font = [UIFont systemFontOfSize:15];
        self.delegate = self;
        [self addSubview:self.placeholderLabel];
        [self sendSubviewToBack:self.placeholderLabel];
    }
    return self;
}

#pragma mark - UITextViewDelegate
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
    if ([self.confiDelegate respondsToSelector:@selector(textViewShouldBeginEditing:)]) {
        return [self.confiDelegate textViewShouldBeginEditing:textView];
    }
    return YES;
}
- (BOOL)textViewShouldEndEditing:(UITextView *)textView {
    if ([self.confiDelegate respondsToSelector:@selector(textViewShouldEndEditing:)]) {
        return [self.confiDelegate textViewShouldEndEditing:textView];
    }
    return YES;
}
- (void)textViewDidBeginEditing:(UITextView *)textView {
    if ([self.confiDelegate respondsToSelector:@selector(textViewDidBeginEditing:)]) {
        [self.confiDelegate textViewDidBeginEditing:textView];
    }
}
- (void)textViewDidEndEditing:(UITextView *)textView {
    if ([self.confiDelegate respondsToSelector:@selector(textViewDidEndEditing:)]) {
        [self.confiDelegate textViewDidEndEditing:textView];
    }
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    if ((self.banBlank && [text isEqualToString:@" "])||//禁止输入空格
        (self.banEmoji && [self stringContainsEmoji:text])||
        (self.banEmoji && [textView.textInputMode.primaryLanguage isEqualToString:@"emoji"])||
        (self.banEmoji && [[[UIApplication sharedApplication]textInputMode].primaryLanguage isEqualToString:@"emoji"])) {//禁止输入表情
        return NO;
    } else if ([text isEqualToString:@"\n"]) {
        if (self.returnShouldResignFirstResponder) {
            [self resignFirstResponder];
        }
        if (self.banLineFeed) {//禁止手动换行
            return NO;
        }
        if ([self.confiDelegate respondsToSelector:@selector(textViewShouldReturn:)]) {
            return [self.confiDelegate textViewShouldReturn:textView];
        } else if ([self.confiDelegate respondsToSelector:@selector(textView:shouldChangeTextInRange:replacementText:)]) {
            return [self.confiDelegate textView:textView shouldChangeTextInRange:range replacementText:text];
        } else {
            return YES;
        }
    } else if (self.maxLength != -1 && text.length > self.maxLength) {
        NSMutableString *textStr = [NSMutableString stringWithString:text];
        text = [textStr stringByReplacingOccurrencesOfString:@" " withString:@""];
        NSMutableString *str = [[NSMutableString alloc]initWithFormat:@"%@%@",textView.text,text];
        if (textView.text.length < self.maxLength) {
            textView.text = [str substringWithRange:NSMakeRange(0, self.maxLength)];
        }
        return NO;
    } else if (self.maxLength != -1 && text.length + textView.text.length > self.maxLength) {
        NSMutableString *str = [[NSMutableString alloc]initWithFormat:@"%@%@",textView.text,text];
        [str replaceCharactersInRange:range withString:@""];
        if (str.length <= self.maxLength) {
            textView.text = str;
        } else {
            UITextRange *selectedRange = [textView markedTextRange];
            UITextPosition *position = [textView positionFromPosition:selectedRange.start offset:0];
            if (!position) {
                textView.text = [str substringWithRange:NSMakeRange(0, self.maxLength)];
                return NO;
            } else {
                if ([self.confiDelegate respondsToSelector:@selector(textView:shouldChangeTextInRange:replacementText:)]) {
                    return [self.confiDelegate textView:textView shouldChangeTextInRange:range replacementText:text];
                }
                return YES;
            }
        }
        return NO;
    } else if (self.maxLength != -1 && textView.text.length >= self.maxLength) {//最大输入长度 self.maxLength
        return  text.length <= 0;
    } else {
        return YES;
    }
}

- (void)textViewDidChange:(UITextView *)textView {
    NSString *lang = [textView textInputMode].primaryLanguage;
    if ([lang isEqualToString:@"zh-Hans"]) {
        //输入简体中文内容
        //获取高亮部分，如拼音
        UITextRange *selectedRange = [textView markedTextRange];
        UITextPosition *position = [textView positionFromPosition:selectedRange.start offset:0];
        if (!position) {
            [self handleTextFieldCharLength:textView];
        }
    } else {
        //输入简体中文以外的内容
        [self handleTextFieldCharLength:textView];
    }
    if (self.dynamicHeight) {
        [self updateTextViewFrameByText:textView.text];
    }
    
    [self updateSureBtnPlaceholderLabenStatue];
    
    if ([self.confiDelegate respondsToSelector:@selector(textViewDidChange:)]) {
        [self.confiDelegate textViewDidChange:textView];
    }
}

- (void)textViewDidChangeSelection:(UITextView *)textView {
    if ([self.confiDelegate respondsToSelector:@selector(textViewDidChangeSelection:)]) {
        [self.confiDelegate textViewDidChangeSelection:textView];
    }
}
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction  API_AVAILABLE(ios(10.0)){
    if ([self.confiDelegate respondsToSelector:@selector(textView:shouldInteractWithURL:inRange:interaction:)]) {
        return [self.confiDelegate textView:textView shouldInteractWithURL:URL inRange:characterRange interaction:interaction];
    }
    return YES;
}
- (BOOL)textView:(UITextView *)textView shouldInteractWithTextAttachment:(NSTextAttachment *)textAttachment inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction API_AVAILABLE(ios(10.0)) {
    if ([self.confiDelegate respondsToSelector:@selector(textView:shouldInteractWithTextAttachment:inRange:interaction:)]) {
        return [self.confiDelegate textView:textView shouldInteractWithTextAttachment:textAttachment inRange:characterRange interaction:interaction];
    }
    return YES;
}
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange API_DEPRECATED_WITH_REPLACEMENT("textView:shouldInteractWithURL:inRange:forInteractionType:", ios(7.0, 10.0)) {
    if ([self.confiDelegate respondsToSelector:@selector(textView:shouldInteractWithURL:inRange:)]) {
        return [self.confiDelegate textView:textView shouldInteractWithURL:URL inRange:characterRange];
    }
    return YES;
}
- (BOOL)textView:(UITextView *)textView shouldInteractWithTextAttachment:(NSTextAttachment *)textAttachment inRange:(NSRange)characterRange API_DEPRECATED_WITH_REPLACEMENT("textView:shouldInteractWithTextAttachment:inRange:forInteractionType:", ios(7.0, 10.0)) {
    if ([self.confiDelegate respondsToSelector:@selector(textView:shouldInteractWithTextAttachment:inRange:)]) {
        return [self.confiDelegate textView:textView shouldInteractWithTextAttachment:textAttachment inRange:characterRange];
    }
    return YES;
}
#pragma mark - custom action
- (void)setAttributedString:(NSAttributedString *)attributedString {
    self.placeholderLabel.hidden = attributedString.length > 0;
    NSMutableAttributedString *tmpAttriString = [[NSMutableAttributedString alloc] initWithAttributedString:attributedString];
    UIFont *selectedFont = [UIFont systemFontOfSize:12];
    //有传递的自定义属性优先使用
    if (self.attributeDic) {
        [tmpAttriString setAttributes:self.attributeDic range:NSMakeRange(0, tmpAttriString.length)];
        if([self.attributeDic objectForKey:NSFontAttributeName]) {
            selectedFont = [self.attributeDic objectForKey:NSFontAttributeName];
        }
    }
    if (self.selectedStrUrlDic.count > 0) {
        NSArray *selectedStringArray = self.selectedStrUrlDic.allKeys;
        for (NSString *selectedString in selectedStringArray) {
            if (![tmpAttriString.string containsString:selectedString]) {
                [tmpAttriString appendAttributedString:[[NSMutableAttributedString alloc] initWithString:selectedString]];
            }
            
            NSRange selectedRange = NSMakeRange(NSNotFound, 0);
            if (selectedString.length > 0) {
                 selectedRange = [tmpAttriString.string rangeOfString:selectedString];
                [self.selectedStrRangeDic setObject: NSStringFromRange(selectedRange) forKey:selectedString];
            } else {
                [self.selectedStrRangeDic setObject: NSStringFromRange(selectedRange) forKey:selectedString];
            }
            
            if(self.selectedAttributeDic) {
                [tmpAttriString setAttributes:self.selectedAttributeDic range:selectedRange];
            }else {
                [tmpAttriString setAttributes:@{NSForegroundColorAttributeName: [UIColor colorWithRed:104.0 / 255.0 green:164.0 / 255.0 blue:222.0 / 255.0 alpha:1.0], NSFontAttributeName: selectedFont} range:selectedRange];
            }
            //选中文字部分默认待下划线
            [tmpAttriString addAttribute:(NSString *)kCTUnderlineStyleAttributeName value:@(kCTUnderlineStyleSingle | kCTUnderlinePatternSolid) range:selectedRange];
        }
    }
    _attributedString = tmpAttriString.copy;
    self.attributedText = _attributedString;
    self.linksArray = nil; // 清空先
}

- (void)textViewDidTouched:(UIGestureRecognizer *)recognizer {
    CGPoint point = [recognizer locationInView:recognizer.view];
    LinkVO *touchingLink = [self touchingLinkWithPoint:point];
    if (touchingLink && [touchingLink isKindOfClass:[LinkVO class]]) {
        if (self.selectedStrUrlDic.count > 0) {
            NSString *selectedString = touchingLink.text;
            NSString *selectedUrlString = [self.selectedStrUrlDic objectForKey:selectedString]?:@"";
            if ([self.confiDelegate respondsToSelector:@selector(titleDidClickedString:urlString:)]) {
                [self.confiDelegate titleDidClickedString:selectedString urlString:selectedUrlString];
            }
        }
    }
}

- (LinkVO *)touchingLinkWithPoint:(CGPoint)point {
    // 查看哪个链接被选中
    __block LinkVO *touchingLink = nil;
    [self.linksArray enumerateObjectsUsingBlock:^(LinkVO *linkVO, NSUInteger idx, BOOL *stop) {
        for (UITextSelectionRect *rect in linkVO.rectsArray) {
            if (CGRectContainsPoint(rect.rect, point)) { // 点击别的地方不会被选中
                touchingLink = linkVO;
                break;
            }
        }
    }];
    return touchingLink;
}
- (void)handleTextFieldCharLength:(UITextView *)textView {
    NSString *toBeString = textView.text;
    if (self.maxLength != -1 && textView.text.length > self.maxLength) {
        //获取超过50最大字符数的多余字符range
        NSRange rangeIndex = [toBeString rangeOfComposedCharacterSequenceAtIndex:self.maxLength];
        if (rangeIndex.length == 1){
            //如果多余字符的length = 1，则直接截取最大字符数
            textView.text = [toBeString substringToIndex:self.maxLength];
        }
        else{
            //如果多余字符的length > 1，则截取位置为（0.50），按输入内容单位截取
            NSRange rangeRange = [toBeString rangeOfComposedCharacterSequencesForRange:NSMakeRange(0, self.maxLength)];
            textView.text = [toBeString substringWithRange:rangeRange];
        }
    }
}
- (void)updateSureBtnPlaceholderLabenStatue {
    if (self.text.length == 0 ) {
        self.placeholderLabel.hidden = NO;
    } else {
        self.placeholderLabel.hidden = YES;
    }
}
- (void)updateTextViewFrameByText:(NSString *)text {
    CGFloat width = self.frame.size.width - (self.textContainerInset.left + self.textContainerInset.right)-10;
    CGSize size = [text boundingRectWithSize:CGSizeMake(width, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:self.font} context:nil].size;
    if (size.height > _minHeight) {
        self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, size.height + (self.textContainerInset.top + self.textContainerInset.bottom));
    } else {
        self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, _minHeight);
    }
}
//表情符号的判断
- (BOOL)stringContainsEmoji:(NSString *)string {
    __block BOOL returnValue = NO;
    [string enumerateSubstringsInRange:NSMakeRange(0, [string length])
                               options:NSStringEnumerationByComposedCharacterSequences
                            usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
        const unichar hs = [substring characterAtIndex:0];
        if (0xd800 <= hs && hs <= 0xdbff) {
            if (substring.length > 1) {
                const unichar ls = [substring characterAtIndex:1];
                const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
                if (0x1d000 <= uc && uc <= 0x1f77f) {
                    returnValue = YES;
                }
            }
        } else if (substring.length > 1) {
            const unichar ls = [substring characterAtIndex:1];
            if (ls == 0x20e3) {
                returnValue = YES;
            }
        } else {
            if (0x2100 <= hs && hs <= 0x27ff) {
                if (0x278b <= hs && hs <= 0x2792) {
                    //自带九宫格拼音键盘
                    returnValue = NO;;
                }else if (0x263b == hs) {
                    returnValue = NO;;
                }else {
                    returnValue = YES;
                }
            } else if (0x2B05 <= hs && hs <= 0x2b07) {
                returnValue = YES;
            } else if (0x2934 <= hs && hs <= 0x2935) {
                returnValue = YES;
            } else if (0x3297 <= hs && hs <= 0x3299) {
                returnValue = YES;
            } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50) {
                returnValue = YES;
            }
        }
    }];
    
    return returnValue;
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    if (![self pointInside:point withEvent:event]) {
        if (self.isFirstResponder) {
            [self resignFirstResponder];
        }
    }
    return  [super hitTest:point withEvent:event];
}
@end
